﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;//引用命名空间
using System.Reflection;
using System.Security;

namespace DllnSpace
{
    public class FunctionInfo
    {
        public string Name;

        public FunctionInfo(string strFuncName)
        {
            Name = strFuncName;
        }
    }
    public unsafe class class1
    {
        public static readonly ushort IMAGE_DIRECTORY_ENTRY_EXPORT = 0;
        private const CallingConvention CALLING_CONVENTION = CallingConvention.Winapi;
        private const string KERNEL_DLL = "kernel32";
        private const string DBGHELP_DLL = "dbghelp";


        [DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "LoadLibrary"), SuppressUnmanagedCodeSecurity]
        public static extern uint LoadLibrary(string lpFileName);


        [DllImport(KERNEL_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "FreeLibrary"), SuppressUnmanagedCodeSecurity]
        public static extern bool FreeLibrary(uint hModule);


        [DllImport(DBGHELP_DLL, CallingConvention = CALLING_CONVENTION, EntryPoint = "ImageDirectoryEntryToData"), SuppressUnmanagedCodeSecurity]
        public static extern void* ImageDirectoryEntryToData(void* Base, bool MappedAsImage, ushort DirectoryEntry, out uint Size);
    }

    public unsafe class ParserDLLClass
    {
        [StructLayout(LayoutKind.Sequential)]
        public struct IMAGE_EXPORT_DIRECTORY
        {
            public UInt32 Characteristics;
            public UInt32 TimeDateStamp;
            public UInt16 MajorVersion;
            public UInt16 MinorVersion;
            public UInt32 Name;
            public UInt32 Base;
            public UInt32 NumberOfFunctions;
            public UInt32 NumberOfNames;
            public UInt32 AddressOfFunctions;     // RVA from base of image
            public UInt32 AddressOfNames;     // RVA from base of image
            public UInt32 AddressOfNameOrdinals;  // RVA from base of image
        }

        [StructLayout(LayoutKind.Explicit)]
        public struct IMAGE_THUNK_DATA32
        {
            [FieldOffset(0)]
            public uint ForwarderString;      // PBYTE 
            [FieldOffset(4)]
            public uint Function;             // PDWORD
            [FieldOffset(8)]
            public uint Ordinal;
            [FieldOffset(12)]
            public uint AddressOfData;        // PIMAGE_IMPORT_BY_NAME
        }

        public static void GetExportFunctionName(string dllPath, ref List<FunctionInfo> listFunc)
        {
            uint handle = class1.LoadLibrary(dllPath);


            if (handle != 0)
            {
                uint size = 0;
                void* baseAddr = (void*)handle;
                IMAGE_EXPORT_DIRECTORY* export = (IMAGE_EXPORT_DIRECTORY*)class1.ImageDirectoryEntryToData((void*)handle, true, class1.IMAGE_DIRECTORY_ENTRY_EXPORT, out size);


                void* ENT = (byte*)baseAddr + export->AddressOfNames; // ExportNameTable


                UInt32 numFunc = export->NumberOfFunctions;
                UInt32* nameTableRVA = (UInt32*)(ENT);
                UInt16* ordinal = (UInt16*)((byte*)baseAddr + export->AddressOfNameOrdinals);


                char* funcName = null;
                for (UInt32 i = 0; i < numFunc; ++i)
                {
                    funcName = (char*)((byte*)baseAddr + nameTableRVA[i]);
                    string strFuncName = Marshal.PtrToStringAnsi((IntPtr)funcName);
                    listFunc.Add(new FunctionInfo(strFuncName));
                }


                class1.FreeLibrary(handle);
            }
        }

        public static string[] getArrFunName(string dllPath)
        {
            List<FunctionInfo> listFunc = new List<FunctionInfo>();

            List<string> listArrFunc = new List<string>();
            DllnSpace.ParserDLLClass.GetExportFunctionName(dllPath, ref listFunc);

            for (int i = 0; i < listFunc.Count;i++ )
            {
                listArrFunc.Add(listFunc[i].Name);
            }
            return listArrFunc.ToArray();
        }

        public static void test()
        {
            string dllPath = @"E:\工作项目\工具开发\检测模板\JiangSuRunTool\JsRunTool\bin\Debug\testDll.dll";
            List<FunctionInfo> listFunc = new List<FunctionInfo>();

            DllnSpace.ParserDLLClass.GetExportFunctionName(dllPath, ref listFunc);
        }
    }

    public class DLLWrapper
    {
        ///<summary> 
        /// API LoadLibrary 
        ///</summary> 
        [DllImport("Kernel32")]
        public static extern int LoadLibrary(String funcname);

        ///<summary> 
        /// API GetProcAddress 
        ///</summary> 
        [DllImport("Kernel32")]
        public static extern int GetProcAddress(int handle, String funcname);

        ///<summary> 
        /// API FreeLibrary 
        ///</summary> 
        [DllImport("Kernel32")]
        public static extern int FreeLibrary(int handle);

        ///<summary> 
        ///通过非托管函数名转换为对应的委托, by jingzhongrong 
        ///</summary> 
        ///<param name="dllModule">通过LoadLibrary获得的DLL句柄</param> 
        ///<param name="functionName">非托管函数名</param> 
        ///<param name="t">对应的委托类型</param> 
        ///<returns>委托实例，可强制转换为适当的委托类型</returns> 
        public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t)
        {
            int address = GetProcAddress(dllModule, functionName);
            if (address == 0)
                return null;
            else
                return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
        }

        ///<summary> 
        ///将表示函数地址的IntPtr实例转换成对应的委托, by jingzhongrong 
        ///</summary> 
        public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t)
        {
            if (address == IntPtr.Zero)
                return null;
            else
                return Marshal.GetDelegateForFunctionPointer(address, t);
        }

        ///<summary> 
        ///将表示函数地址的int转换成对应的委托，by jingzhongrong 
        ///</summary> 
        public static Delegate GetDelegateFromIntPtr(int address, Type t)
        {
            if (address == 0)
                return null;
            else
                return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
        }

        //public static extern string getEncKey(string path1, int mode);
        //delegate string FOO([MarshalAs(UnmanagedType.LPWStr)]String FileName,int FileNum);
        delegate string FOO(string FileName, int FileNum);

        public static bool test(string dllFilePath)
        {
            int hModule = DLLWrapper.LoadLibrary(dllFilePath);
            if (hModule == 0)
                return false;

            //3、获取相应的委托实例： 
            FOO foo = (FOO)DLLWrapper.GetFunctionAddress(hModule, "getEncKey", typeof(FOO));
            if (foo == null)
            {
                DLLWrapper.FreeLibrary(hModule);
                return false;
            }
            
            string str = foo("T1607028", 0);
            return false;
        }
    }
}
